<?php
function filemanager_admin() {
  $form = array();
  $form['filemanager_maxdepth'] = array(
    '#type' => 'textfield',
    '#title' => 'Maximum directory depth',
    '#description' => 'The maximum directory depth in the file viewer.',
    '#default_value' => variable_get('filemanager_maxdepth', 3),
    '#size' => 3,
    '#maxlength' => 3,
  );
  
  return system_settings_form($form);
}

function filemanager_admin_validate($form, &$form_state) {
  $maxdepth = $form_state['values']['filemanager_maxdepth'];
  if(!is_numeric($maxdepth)) {
    form_set_error('filemanager_maxdepth','The maximum directory depth must be an integer.');
  } else if($maxdepth <= 0) {
    form_set_error('filemanager_maxdepth','The maximum directory depth must be greater than zero.');
  }
}
function filemanager_admin_submit($form, &$form_state) {
  $maxdepth = $form_state['values']['filemanager_maxdepth'];
  variable_set('filemanager_maxdepth', $maxdepth);
}

function filemanager_fileviewer() {
  $path = filemanager_normal_path($_GET['d']);
  if(!$path) $path = file_directory_path().'/';
  $form = filemanager_build_file_tree($path, variable_get('filemanager_maxdepth', 3), false);
  $form['#attributes'] = array('enctype' => 'multipart/form-data');
  $form['fileviewer']['ops']['op-delete'] = array(
    '#type' => 'submit',
    '#value' => 'Delete selected files',
  );
  $form['fileviewer']['ops']['op-permanent'] = array(
    '#type' => 'submit',
    '#value' => 'Make selected files permanent',
  );
  $form['fileviewer']['ops']['op-temp'] = array(
    '#type' => 'submit',
    '#value' => 'Clean temporary files',
  );
  
  $form['file-uploader'] = filemanager_upload_form();
  
  $form['file-move-copy'] = filemanager_move_copy_form();
  return $form;
}


/**
 * Generates a file upload form.
 * 
 * Use filemanager_upload_form_operate() to process.
 */
function filemanager_upload_form($collapsed=true, $submit=true) {
  $form = array(
    '#type' => 'fieldset',
    '#title' => 'Upload file',
    '#collapsible' => true,
    '#collapsed' => (bool) $collapsed,
  );
  $form['upload-source'] = array(
    '#type' => 'file',
    '#title' => 'Choose file',
    '#size' => 24,
  );
  $form['upload-dest'] = array(
    '#type' => 'textfield',
    '#title' => 'Choose destination (optional)',
    '#description' => t('Location to upload file to on the server. Defaults to ').file_directory_path(),
    '#default_value' => file_directory_path(),
    '#size' => 32,
  );
  $form['upload-dest-name'] = array(
    '#type' => 'textfield',
    '#title' => 'Choose destination filename (optional)',
    '#description' => t('Name of file uploaded to server. Defaults to filename of upload.'),
    '#size' => 32,
  );
  if($submit) {
    $form['upload-submit'] = array(
      '#type' => 'submit',
      '#value' => 'Upload file',
    );
  }
  return $form;
}

/**
 * Operates on a form submission from filemanager_upload_form()
 * 
 * This function can be used in the implementation of hook_submit() -or-
 * hook_validate(), depending on how your form needs to move.
 */
function filemanager_upload_form_operate($form, &$form_state) {
  $dest = $form_state['values']['upload-dest'];
  if($dest == '') $dest = file_directory_path();
  
  $name = $form_state['values']['upload-dest-name'];
  if($name == '') $name = false;
  $file = filemanager_upload_file('upload-source', array(), $dest, $name);
  return $file;
}
/**
 * Generates a file move/copy form
 * 
 * Use the function filemanager_move_copy_form_operate() to process.
 */
function filemanager_move_copy_form($collapsed=true, $submit=true, $file=false) {
  $form = array(
    '#type' => 'fieldset',
    '#title' => 'Copy/move file',
    '#collapsible' => true,
    '#collapsed' => $collapsed,
  );
  if(!$file) $src = file_directory_path();
  else $src = $file->filepath;
  $form['cm-source'] = array(
    '#type' => 'textfield',
    '#title' => 'Choose source',
    '#description' => t('Location to upload file to on the server. Defaults to ').file_directory_path(),
    '#default_value' => $src,
    '#size' => 32,
  );
  $form['cm-radios'] = array(
    '#type' => 'radios',
    '#options' => array('copy' => 'copy file','move' => 'move file'),
    '#default_value' => 'copy file',
  );
  $form['cm-dest'] = array(
    '#type' => 'textfield',
    '#title' => 'Choose destination',
    '#description' => t('Location to upload file to on the server.'),
    '#default_value' => file_directory_path(),
    '#size' => 32,
  );
  $form['cm-dest-name'] = array(
    '#type' => 'textfield',
    '#title' => 'Choose destination filename (optional)',
    '#description' => t('Name of new file. Defaults to filename of original.'),
    '#size' => 32,
  );
  if($submit) {
    $form['cm-submit'] = array(
      '#type' => 'submit',
      '#value' => 'Copy/move file',
    );
  }
  return $form;
}

/**
 * Operates on a form submission from filemanager_move_copy_form()
 * 
 * This function can be used in the implementation of hook_submit() -or-
 * hook_validate(), depending on how your form needs to move.
 */
function filemanager_move_copy_form_operate($form, &$form_state) {
  // Get form values
  $cm = $form_state['values']['cm-radios'];
  $source = $form_state['values']['cm-source'];
  $dest = $form_state['values']['cm-dest'];
  $name = $form_state['values']['cm-dest-name'];
  
  // Check whether or not to specify a filename
  if($name == '') $name = false;
  
  // Copy or move based on radio state
  if($cm == 'copy') {
    $result = filemanager_copy_file($source, $dest, $name);
  } else if($cm == 'move') {
    $result = filemanager_move_file($source, $dest, $name);
  }
  if(!$result) return false;
  else return $source;
}
/**
 * Validates a form submission from filemanager_fileviewer()
 */
function filemanager_fileviewer_validate($form, &$form_state) {
  $action = $form_state['clicked_button']['#value'];
  
  switch($action) {
    case 'Upload file':
      $upload = filemanager_upload_form_operate($form, $form_state);
      if(!$upload) form_set_error('file-uploader', t("File upload failed"));
      break;
    case 'Copy/move file':
      $move_copy = filemanager_move_copy_form_operate($form, $form_state);
      if(!$move_copy) form_set_error('file-move-copy', t("File move failed"));
      break;
    default:
      form_set_error(null, 'Hax0r');
      break;
  }
}
/**
 * Submits a form from filemanager_fileviewer()
 * 
 * TODO: decide whether or not to merge _validate() and _submit(). Leaning towards merge 'em.
 */
function filemanager_fileviewer_submit($form, &$form_state) {
  $action = $form_state['clicked_button']['#value'];
  
  switch($action) {
    case 'Delete selected files':
      $post = $form_state['clicked_button']['#post'];
      foreach($post as $fid => $selected) {
        if(is_numeric($fid) && $selected == 'selected') {
          filemanager_delete_file($fid);
          drupal_set_message('Deleted fid '.$fid, 'status');
        }
      }
      break;
    case 'Make selected files permanent':
      $post = $form_state['clicked_button']['#post'];
      foreach($post as $fid => $selected) {
        if(is_numeric($fid) && $selected == 'selected') {
          $file = filemanager_get_file_record('fid', $fid);
          if($file->status == FILE_STATUS_PERMANENT) {
            drupal_set_message(t("%file already permanent.", array('%file' => $file->filename)), 'warning');
          } else {
            file_set_status($file, FILE_STATUS_PERMANENT);
            drupal_set_message(t('Made %file permanent', array('%file' => $file->filename)), 'status');
          }
        }
      }
      break;
    case 'Clean temporary files':
      $result = db_query("DELETE FROM {files} WHERE status='%d'", FILE_STATUS_TEMPORARY);
      if(!$result) drupal_set_message(t("Error while cleaning temporary files."), 'error');
      else drupal_set_message(t("Temporary files cleaned."), 'status');
      break;
      
    case 'Upload file':
      drupal_set_message('File uploaded', 'status');
      break;
  }
}
/**
 * Build the file tree.
 * 
 */
function filemanager_build_file_tree($dir, $maxdepth, $radios) {
  // Generate directory paths--real path to chosen directory and "normal" path to directory
  $realdir = realpath($dir);
  $normdir = filemanager_normal_path($dir);
  
  // Check that destination directory exists
  if(!file_exists($realdir)) {
    // If not, default to Drupal files directory
    drupal_set_message(t("Directory ").$dir.t(" doesn't exist. Defaulting to Drupal files directory."));
    $dir2 = file_directory_path();
    $realdir = realpath($dir2);
    $normdir = filemanager_normal_path($dir);
  }
  
  // Query for files starting with $normdir
  $dirname_length = strlen($normdir);
  $db_result = db_query("SELECT * FROM {files} WHERE '%s'=SUBSTRING({files}.filepath, 1, %d) ORDER BY filepath", $normdir, $dirname_length);
  
  $files = array();
    
  
  // Loop through query results
  while($file = db_fetch_object($db_result)) {
    // If fetch returns false, there aren't any more rows, so break loop
    if(!$file) break;
    
    // Make file path "normal"
    $path = filemanager_normal_path($file->filepath);
    // Get real path to file
    $realpath = realpath($path);
    // Handle missing files
    if(!$realpath) continue;
    
    $path = substr($realpath, strlen(dirname($realdir).'/'));
    
    $path_array = explode(DIRECTORY_SEPARATOR, $path);
    if($path_array[0]=='') array_shift($path);
    $path_array[] = $file;
    
    build_tree($files, $path_array, $maxdepth);
  }
  
  $updir = filemanager_normal_path(dirname($realdir)).'/';
  if($updir == '/') $updir = '';
  return form_from_tree($files, $updir, $radios, true);
}

function sort_by_type($a, $b) {
  if(is_array($a) and is_array($b)) return 0;
  if(is_array($a) and $b == null) return -1;
  if(is_object($a) and $b == null) return 1;
  if(is_array($a) and is_object($b)) return 1;
}

function form_from_tree($array, $dir, $radios=false, $show_above=false) {
  $folderurl = $GLOBALS['base_url'] . "/modules/filemanager/folder.png";
  $form = array();
  uasort($array,'sort_by_type');
  foreach($array as $key => $value) {
    if(is_array($value)) {
      $item_name = $dir.$key.'/';
      if(is_object($value[key($value)]) || count($value) > 1 || !isset($value[key($value)])) {
        $header = '<div class="fileinfobox-header">'.
                  '<div class="fileinfo checkbox"><input type="checkbox" checked="checked" disabled="disabled" /></div>'.
                  '<div class="fileinfo filename">Filename</div>'.
                  '<div class="fileinfo filepath">File path</div>'.
                  '<div class="fileinfo filemime">MIME type</div>'.
                  '<div class="fileinfo filesize">File size</div>'.
                  '</div>';
      } else $header = '';
      $hrefdir = l(shorten_path($dir, 255), 'admin/settings/fileviewer', array('query' => array('d' => $dir)));
      $hrefitem = l($key.'/', 'admin/settings/fileviewer', array('query' => array('d' => $item_name)));
      if($show_above && $dir != '') {
        $form['fileviewer'][$item_name]['open'] = array(
          '#type' => 'markup',
          '#value' => '<p class="dirname"><img src="'.$folderurl.'" alt="" class="folder" />'.$hrefdir.'</p><div class="directory">'.
                      '<p class="dirname"><img src="'.$folderurl.'" alt="" class="folder" />'.$hrefitem.'</p><div class="directory">'.$header,
        );
      } else {
        $form['fileviewer'][$item_name]['open'] = array(
          '#type' => 'markup',
          '#value' => '<p class="dirname"><img src="'.$folderurl.'" alt="" class="folder" />'.$hrefitem.'</p><div class="directory">'.$header,
        );
      }
      $form['fileviewer'][$item_name]['contents'] = form_from_tree($value, $dir.$key.'/', $radios);
      if($show_above) {
        $form['fileviewer'][$item_name]['close'] = array(
          '#type' => 'markup',
          '#value' => '</div></div>',
        );
      } else {
        $form['fileviewer'][$item_name]['close'] = array(
          '#type' => 'markup',
          '#value' => '</div>',
        );
      }
    } else if(is_object($value)) { 
      $item_name = $dir.$key;
      $status = $value->status;
      if($status == FILE_STATUS_TEMPORARY) {
        $class = ' file-temporary';
      } else $class = '';
      if($radios) {
        $form['fileviewer'][$item_name]['choose-file'] = array(
          '#prefix' => '<div class="fileinfo">',
          '#type' => 'radio',
          '#return_value' => $value->fid,
          '#suffix' => '<p>'.$value->filename.'</p></div>',
        );
      } else {
        $form['fileviewer'][$item_name][$value->fid] = array(
          '#prefix' => '<div class="filebox"><div class="fileinfo checkbox">',
          '#type' => 'checkbox',
          '#return_value' => 'selected',
          '#suffix' =>  '</div>'.
                        '<div class="fileinfo filename'.$class.'" title="'.$value->filename.'">'.shorten_name($value->filename,15).'</div>'.
                        '<div class="fileinfo filepath" title="'.$value->filepath.'">'.shorten_path($value->filepath,20).'</div>'.
                        '<div class="fileinfo filemime">'.$value->filemime.'</div>'.
                        '<div class="fileinfo filesize">'.format_filesize($value->filesize).'</div>'.
                        '</div>',
        );
      }
    } else if(!isset($value)) {
      $item_name = $dir.$key.'/';
        $hrefitem = l($key.'/', 'admin/settings/fileviewer', array('query' => array('d' => $item_name)));
      $form['fileviewer'][$item_name] = array(
        '#type' => 'markup',
        '#value' => '<div class="filebox">'.
                    '<div class="fileinfo checkbox"><img src="'.$folderurl.'" alt="" class="folder" /></div>'.
                    '<div class="fileinfo filename">'.$hrefitem.'</div>'.
                    '<div class="fileinfo filepath" title="'.$item_name.'">'.shorten_path($item_name,20).'</div>'.
                    '<div class="fileinfo filemime">directory</div>'.
                    '<div class="fileinfo filesize">--</div>'.
                    '</div>',
      );
    }
  }
  return $form;
}

function shorten_path($text, $length) {
  if(strlen($text) > $length) {
    return '...'.substr($text,strlen($text)-$length, $length);
  } else return $text;
}

function shorten_name($text, $length) {
  if(strlen($text) > $length) {
    return substr($text,0, $length).'...';
  } else return $text;
}

function format_filesize($size) {
  if($size < 1024) return $size.' B';
  if($size > 1024 && $size < 1048576) return round($size / 1024,2).' KiB';
  if($size > 1048576 && $size < 1073741824) return round($size / 1048576,2).' MiB';
  if($size > 1073741824) return round($size / 1073741824,2).' GiB';
}

function build_tree(&$key, $array, $maxdepth) {
  if(count($array) > 1) {
    $k = $array[0];
    $key[$k];
    array_shift($array);
    if($maxdepth > 0) {
    build_tree($key[$k], $array, $maxdepth-1);
    }
  } else {
    $key = $array[0];
  }
}